﻿/*
 * SqEngine 0.5.1
 * Date 29/08/2009 
 * by squid <squid@stormwind.it>
 * web: http://squareengine.codeplex.com
 * WebBrowser Component Pool
 * Render on 2D Texture
 */
#region Using
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using sqengine.Engine.Common;
using System.Threading;
using System.Collections;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using SqEngine;
using CjcAwesomiumWrapper;


#endregion

namespace sqengine.Components
{

    #region NativeMethods
    public enum Win32Message
    {
        WM_KEYDOWN = 0x100,
        WM_KEYUP = 0x101,
        WM_CHAR = 0x102,
        WM_SYSKEYDOWN = 0x104,
        WM_SYSKEYUP = 0x105,
        WM_SYSCHAR = 0x106,
        WM_SYSDEADCHAR = 0x107,
        WM_MOUSEDOWN = 0x201
    }

    [Flags]
    public enum ControlKeyStates
    {
        CapsLockOn = 0x80,
        EnhancedKey = 0x100,
        LeftAltPressed = 2,
        LeftCtrlPressed = 8,
        NumLockOn = 0x20,
        RightAltPressed = 1,
        RightCtrlPressed = 4,
        ScrollLockOn = 0x40,
        ShiftPressed = 0x10
    }


    #endregion

    public class WebBrowserPool : Microsoft.Xna.Framework.GameComponent
    {
        // Pool size. 
        private const int POOL_SIZE = 5;
        private WebCore webcore = new WebCore();

        private int browser_count = -1;
        WebView[] webview_pool = new WebView[POOL_SIZE];
        WebViewListener[] weblist_pool = new WebViewListener[POOL_SIZE];
        Texture2D[] textures_pool = new Texture2D[POOL_SIZE];
        byte[][] buffer_pool = new byte[POOL_SIZE][];

       
        public WebBrowserPool(Game game)
            : base(game)
        {

        }

        private void RenderThread()
        {
            webcore.Update();

            if (webview_pool.Length > 0)
            {
                for (int i = 0; i < webview_pool.Length - 1; i++)
                {
                    if (webview_pool[i] != null)
                    {
                        RenderWebpage(i);
                    }
                }
            }            
        }
        
        /// <summary>
        /// Add web window and return ID of pool
        /// </summary>
        /// <param name="width">Width of window</param>
        /// <param name="height">Height of window</param>
        /// <returns>ID of thread if return is -1 there is a problem</returns>
        public int AddWebWindow(int width, int height)
        {
            int id_window = -1;

            if (width > 0 && height > 0)
            {
                WebView webview = webcore.CreateWebView(width, height);
                byte[] w_buffer = new byte[width * height * 4];

                Texture2D w_texture = new Texture2D(this.Game.GraphicsDevice, width, height, 1, TextureUsage.AutoGenerateMipMap, SurfaceFormat.Bgr32);

                id_window = GetFreeId();                

                WebViewListener w_listner = new WebViewListener();

                webview_pool[id_window] = webview;

                buffer_pool[id_window] = w_buffer;
                textures_pool[id_window] = w_texture;
                weblist_pool[id_window] = w_listner;

                webview_pool[id_window].SetListener(weblist_pool[id_window]);

                webview = null;
                w_buffer = null;
                w_texture = null;

                browser_count++;
            }

            return id_window;

        }

        

        public override void Update(GameTime gameTime)
        {
            RenderThread();

            base.Update(gameTime);
        }

        private int GetFreeId()
        {
            int id = -1;

            for (int i = 0; i < webview_pool.Length - 1; i++)
            {
                if (webview_pool[i] == null)
                {
                    id = i;
                    break;
                }
            }

            return id;

        }
        private void RenderWebpage(int id)
        {
            if (webview_pool[id] != null && webview_pool[id].IsDirty() && textures_pool[id] != null && buffer_pool[id] != null)
            {

                webview_pool[id].Render(buffer_pool[id], textures_pool[id].Width * 4, 4);
                CjcAwesomiumWrapper.Rect rect = webview_pool[id].Render(buffer_pool[id], textures_pool[id].Width * 4, 4);

                textures_pool[id].SetData<byte>(buffer_pool[id]);
            }

        }


        /// <summary>
        /// Get Render Texture 2d
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Texture2D GetRendererWebpage(int id)
        {
            if (id != -1)
            {
                if (textures_pool[id] != null)
                    return textures_pool[id];
                else
                    return null;
            }
            else
                return null;
        }


        /// <summary>
        /// Function for navigate webbrowser
        /// </summary>
        /// <param name="id"></param>
        /// <param name="url"></param>
        public void Navigate(int id, string url)
        {
            if (webview_pool[id] != null && !string.IsNullOrEmpty(url))
            {
                if (!url.Contains("http://"))
                    url = "http://" + url;

                webview_pool[id].LoadURL(url);

            }
        }

        /// <summary>
        /// Use this method if you want open local file
        /// </summary>
        /// <param name="filename">ex: c:/myweb.html</param>
        public void NavigateFile(int id, string filename)
        {
            if (webview_pool[id] != null) webview_pool[id].LoadFile(filename);
        }

        public void RemoveWebWindow(int id)
        {
            webview_pool[id] = null;
            buffer_pool[id] = null;
            textures_pool[id] = null;
            weblist_pool[id] = null;

            CheckEmptyPool();

        }

        public void SetFocus(int id)
        {
            if (webview_pool[id] != null) webview_pool[id].Focus();
        }

        public void SetCallback(int id, string callback)
        {
            if (webview_pool[id] != null)
                webview_pool[id].SetCallback(callback);

        }
        private void CheckEmptyPool()
        {
            bool empty = false;

            for (int i = 0; i < webview_pool.Length; i++)
            {
                if (webview_pool[i] != null)
                    empty = true;
            }


        }

        #region Mouse Injection
        public void InjectMouseMove(int id, int x, int y)
        {
            if (webview_pool[id] != null)
                webview_pool[id].InjectMouseMove(x, y);
        }

        public void InjectMouseButtonDown(int id, MouseButton button)
        {
            if (webview_pool[id] != null)
                webview_pool[id].InjectMouseDown(button);
        }

        public void InjectMouseButtonUp(int id, MouseButton button)
        {
            if (webview_pool[id] != null)
                webview_pool[id].InjectMouseUp(button);
        }

        public void InjectMouseWheel(int id, int val)
        {
            if (webview_pool[id] != null)
                webview_pool[id].InjectMouseWheel(val);
        }

        #endregion

        #region Event Attacher
        public void AttachFinishLoading(int id, WebViewListener.FinishLoadingDelegate FinishLoading)
        {
            if (weblist_pool[id] != null)
                weblist_pool[id].FinishLoading += new WebViewListener.FinishLoadingDelegate(FinishLoading);
        }

        public void AttachBeginLoading(int id, WebViewListener.BeginLoadingDelegate BeginLoading)
        {
            if (weblist_pool[id] != null)
                weblist_pool[id].BeginLoading += new WebViewListener.BeginLoadingDelegate(BeginLoading);
        }


        public void AttachReceiveTitle(int id, WebViewListener.ReceiveTitleDelegate ReceiveTitle)
        {
            if (weblist_pool[id] != null)
                weblist_pool[id].ReceiveTitle += new WebViewListener.ReceiveTitleDelegate(ReceiveTitle);
        }

        public void AttachBeginNavigation(int id, WebViewListener.BeginNavigationDelegate BeginNavigation)
        {
            if (weblist_pool[id] != null)
                weblist_pool[id].BeginNavigation += new WebViewListener.BeginNavigationDelegate(BeginNavigation);
        }

        public void AttachCallback(int id, WebViewListener.CallbackDelegate CallbackDelegate)
        {
            if (weblist_pool[id] != null)
                weblist_pool[id].Callback += new WebViewListener.CallbackDelegate(CallbackDelegate);

        }

        public void AttachChangeCursor(int id, WebViewListener.ChangeCursorDelegate ChangeCursor)
        {
            if (weblist_pool[id] != null)
                weblist_pool[id].ChangeCursor += new WebViewListener.ChangeCursorDelegate(ChangeCursor);

        }
        #endregion

        #region Keyboard injection

        public void InjectKeyboardEvent(int id, Win32Message message, byte virtualKeyCode, bool isExtended, bool contextCode, bool previousState, bool transitionState)
        {
            if (webview_pool[id] != null)
            {
                var lParam = new KeyLParam(1, virtualKeyCode, isExtended, contextCode, previousState, transitionState);
                webview_pool[id].InjectKeyboardEvent((IntPtr)0, (int)message, virtualKeyCode, lParam);
            }
        }

        public void InjectKey(int id, byte chr)
        {
            InjectKeyboardEvent(id, Win32Message.WM_KEYDOWN, chr, false, false, false, false);
            InjectKeyboardEvent(id, Win32Message.WM_KEYUP, chr, false, false, false, false);
        }

        public void InjectChr(int id, byte chr)
        {
            InjectKeyboardEvent(id, Win32Message.WM_CHAR, chr, false, false, false, false);
            InjectKeyboardEvent(id, Win32Message.WM_KEYUP, chr, false, false, false, false);
        }


        #endregion
    }
}
